package lsp.timer;

import lsp.base.LspPacket;
import lsp.base.LspParams;
import lsp.base.PacketStatus;
import lsp.connector.IConnector;

public class LspTimer implements Runnable {
	
	private IConnector connector;
	private LspParams params;
	
	private boolean started;
	private int counter;
	private long initialTime;

	public LspTimer(IConnector connector, LspParams params) {
		this.connector = connector;
		this.params = params;
	}
	
	@Override
	public void run() {
		stopTimer();
		LspPacket packet = null;
		while (true) {
			packet = connector.getCurrentLspPacket();
			if (packet != null) {
				if (packet.getPacketStatus() == PacketStatus.WAITING_ACK) {
					if (!started) {
						startTimer();
					} else {
						if (timeout()) {
							if (!attemptLimitExceeded()) {
								resendPacket();
							} else {
								cancelPacket();
							}
						}
					}
				} else if (packet.getPacketStatus() == PacketStatus.ACK_RECEIVED) {
					if (started) {
						stopTimer();
					}
				}
			}
			
			try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				// interrupted: terminate execution
				return;
			}
		}
		
	}

	private void cancelPacket() {
		connector.getCurrentLspPacket().setPacketStatus(PacketStatus.CANCELED);
		stopTimer();
	}

	private boolean attemptLimitExceeded() {
		return counter >= params.getEpochLimit();
	}

	private void resendPacket() {
		connector.getCurrentLspPacket().setPacketStatus(PacketStatus.RESEND);
		counter++;
		started = false;
	}

	private boolean timeout() {
		return elapsedTime() > params.getEpoch();
	}

	public long elapsedTime() {
		return System.currentTimeMillis() - initialTime;
	}

	private void startTimer() {
		started = true;
		initialTime = System.currentTimeMillis();
	}

	private void stopTimer() {
		started = false;
		initialTime = -1;
		counter = 0;
	}

	public boolean isStarted() {
		return started;
	}
	
}
